home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / Libraries / MoreFinderEvents / MoreFinderEvents.cp next >
Encoding:
Text File  |  1996-07-01  |  20.3 KB  |  805 lines  |  [TEXT/CWIE]

  1.     //
  2.     //    MoreFinderEvents 1.0
  3.     //    ====================
  4.     //
  5.     //    an AppleEvents package for non-scriptable versions of Finder
  6.     //
  7.     //    by Pete Gontier, Apple Macintosh Developer Technical Support
  8.     //
  9.     //    Copyright (c) 1996 Apple Computer, Inc., All Rights Reserved.
  10.     //
  11.     //    Complaints and kudos to: <gurgle@apple.com>
  12.     //
  13.     //    Thanks to Jon Pugh for 'FinderEvents.p' XCMD and code review
  14.     //    of this package.
  15.     //
  16.     //    INTRODUCTION
  17.     //    ============
  18.     //
  19.     //    The AppleEvents API is icky and you probably don't relish the
  20.     //    idea of developing an intimate relationship with it. And you
  21.     //    don't feel your application should yet require the scriptable
  22.     //    Finder, which first shipped in System 7.5. Yet you still want
  23.     //    to make Finder do backflips and cartwheels.
  24.     //
  25.     //    Enter MoreFinderEvents.
  26.     //
  27.     //    This package provides you with a painless API for sending some
  28.     //    of the more simple forms of the FinderEvents, which have been
  29.     //    with us since System 7.0.0. With this API you can copy a
  30.     //    file or open a control panel or empty the trash or any of
  31.     //    several other things usually done by Finder at the user's
  32.     //    request.
  33.     //
  34.     //    THEORY OF OPERATION
  35.     //    ===================
  36.     //
  37.     //    There's nothing terribly tricky here. We're just using the
  38.     //    AppleEvents API along with some simple C++ code to make it
  39.     //    a little more palatable. The only thing worth noting is that
  40.     //    Finder doesn't use the AppleEvents API on its end. Apparently
  41.     //    the Finder which shipped with System 7.0.0 needed to feature-
  42.     //    freeze before the AppleEvent Manager, so it has its own code
  43.     //    for examining AppleEvents. Since the Finder code is tailored
  44.     //    specifically to support FinderEvents, it tends to get cranky
  45.     //    when fed data which is not absotively posilutely correct.
  46.     //    If you modify this library and Finder starts crashing, that's
  47.     //    probably why.
  48.     //
  49.     //    BUILDING
  50.     //    ========
  51.     //
  52.     //    I wrote this library intermittently over a period of months with
  53.     //    with Metrowerks CodeWarrior CW7, CW8, and CW9. Consequently,
  54.     //    I don't know for certain whether it compiles with any other
  55.     //    compilers, although it's Universal Headers 2.0-savvy and should
  56.     //    work just fine.
  57.     //
  58.     //    Note that despite the fact that this is C++ code, all entry
  59.     //    points (the function prototypes in "MoreFinderEvents.h") are
  60.     //    declared 'pascal', meaning you can call this code from C and
  61.     //    Pascal. There's no Pascal interface file for this library
  62.     //    at the moment primarily because to me an interface file would
  63.     //    imply that the author had ported "TestFinderEvents.c" to Pascal
  64.     //    to make sure the interface file worked. If someone wants to do
  65.     //    that and send me the results, I'll be more than happy to include
  66.     //    them in future versions of this package.
  67.     //
  68.     //    KNOWN PROBLEMS
  69.     //    ==============
  70.     //
  71.     //    [1] One of the following two things is true:
  72.     //
  73.     //        [a] The handling of 'iconPosition' in
  74.     //        'MFE_DragLow' is buggy.
  75.     //
  76.     //        [b] Finder doesn't handle this parameter properly.
  77.     //
  78.     //    The practical effect is that the icon lands in an unpredictable
  79.     //    position in the destination folder window.
  80.     //
  81.     //    [2] Some FinderEvents result in Finder behavior which doesn't
  82.     //    work well unless Finder is the front application. For example,
  83.     //    you can submit a request to open the Page Setup dialog for a
  84.     //    given folder window and Finder will happily open the Printing
  85.     //    Manager and the appropriate dialog from the background. When
  86.     //    the user brings Finder forward, the dialog won't (always) update
  87.     //    properly. Bad. It's not clear what to do about this; some
  88.     //    developers would probably rather decide for themselves when to
  89.     //    bring Finder forward. I'd love to hear your feedback.
  90.     //
  91.     //    [3] It's been suggested you're better off using the scriptable
  92.     //    Finder. It's said these older FinderEvents will go away
  93.     //    eventually. These things are true, so you should use the
  94.     //    scriptable Finder if it's available. See 'd e v e l o p'
  95.     //    magazine, issue 20, pages 65 to 78 for details. Does this
  96.     //    mean you'll have two chunks of code in your application?
  97.     //    Well... er... yes. Maybe someday I'll update this library so
  98.     //    that a single call will work regardless of the presence of
  99.     //    a scriptable Finder. Wouldn't that be cool?
  100.     //
  101.     //    TO DO
  102.     //    =====
  103.     //
  104.     //    There are a few events defined in Chapter 8 of the AppleEvents
  105.     //    Registry for which I have not yet implemented glue. If you're
  106.     //    a squeaky wheel, I'll try to make sure you get some grease.
  107.     //
  108.     //        move window
  109.     //        size window
  110.     //        zoom window
  111.     //        set view
  112.     //
  113.     //    LEGAL NOTICE
  114.     //    ============
  115.     //
  116.     //     You may incorporate this sample code into your applications
  117.     //     without restriction. This sample code has been provided "AS
  118.     //     IS" and the responsibility for its operation is 100% yours.
  119.     //     You are not permitted to redistribute the source as "Apple
  120.     //     sample code" after having made changes. If you're going to
  121.     //     re-distribute the source, we require that you make it clear
  122.     //     in the source that the code was descended from Apple sample
  123.     //     code, but that you've made changes.
  124.     //
  125.  
  126. #define SystemSevenOrLater        1
  127. #define OLDROUTINELOCATIONS        0
  128. #define OLDROUTINENAMES            0
  129.  
  130. #include "MoreFinderEvents.h"
  131.  
  132. #ifndef __AEREGISTRY__
  133. #    include <AERegistry.h>
  134. #endif
  135.  
  136. #ifndef __APPLEEVENTS__
  137. #    include <AppleEvents.h>
  138. #endif
  139.  
  140. #if PRAGMA_ALIGN_SUPPORTED
  141. #    pragma push
  142. #    pragma options align=mac68k
  143. #endif
  144.  
  145. struct MFE_Window
  146. {
  147.     long            fWindowType;
  148.     DescType        fAliasType;
  149.     long            fAliasLen;
  150.     AliasRecord        fAliasRecord;
  151. };
  152.  
  153. typedef MFE_Window *MFE_WindowP, **MFE_WindowH;
  154.  
  155. struct FinderEvent : public AppleEvent
  156. {
  157.     OSErr        fErr;
  158.     AppleEvent    fReply;
  159.     AESendMode    fSendMode;
  160.  
  161.     FinderEvent (AEEventClass,AEEventID);
  162.     ~FinderEvent (void);
  163.     OSErr Send (void);
  164. };
  165.  
  166. #if PRAGMA_ALIGN_SUPPORTED
  167. #    pragma pop
  168. #endif
  169.  
  170. enum
  171. {
  172.     kCreatorCode_Finder = 'MACS',
  173.     kCreatorCode_AtEase = 'mfdr'
  174. };
  175.  
  176. static pascal OSErr GetCreatorOfFinderLikeProcess (OSType *processSignature)
  177. {
  178.     OSErr err = noErr;
  179.  
  180.     ProcessSerialNumber        psn        = { kNoProcess, kNoProcess };
  181.     ProcessInfoRec            pir        = { sizeof (pir), nil };
  182.  
  183.     *processSignature = 0;
  184.  
  185.     pir.processAppSpec = nil;
  186.  
  187.     for (;;)
  188.     {
  189.         err = GetNextProcess (&psn);
  190.         if (err)
  191.         {
  192.             if (err == procNotFound) err = noErr;
  193.             break;
  194.         }
  195.  
  196.         err = GetProcessInformation (&psn,&pir);
  197.         if (err) break;
  198.  
  199.         if (pir.processSignature == kCreatorCode_Finder ||
  200.             pir.processSignature == kCreatorCode_AtEase)
  201.         {
  202.             *processSignature = pir.processSignature;
  203.             break;
  204.         }
  205.     }
  206.  
  207.     return err;
  208. }
  209.  
  210. /////////////////////////////////////////////////////////////////////////////////
  211. #pragma mark -
  212.  
  213. /*
  214.  
  215. // cheap 68K-only debugging tool
  216.  
  217. static pascal asm void DisassembleAppleEvent (AEDesc *)
  218. {
  219.     MOVE.L    (A7)+,A0
  220.     MOVE.L    (A7)+,A1
  221.     PEA        @1
  222.     DC.W    0xABFF
  223.     JMP        (A0)
  224. @1:    DC.B "\p ; aevt rA1"
  225. }
  226.  
  227. */
  228.  
  229. OSErr FinderEvent::Send (void)
  230. {
  231.     return fErr = AESend (this,&fReply,fSendMode,kAENormalPriority,-1,nil,nil);
  232. }
  233.  
  234. FinderEvent::FinderEvent (AEEventClass eventClass, AEEventID eventID)
  235. {
  236.     OSType finderLikeProcess;
  237.  
  238.     descriptorType            = typeNull;
  239.     dataHandle                = nil;
  240.     fReply.descriptorType    = typeNull;
  241.     fReply.dataHandle        = nil;
  242.  
  243.     if (!(fErr = GetCreatorOfFinderLikeProcess (&finderLikeProcess)))
  244.     {
  245.         AEAddressDesc address;
  246.         if (!(fErr = AECreateDesc (typeApplSignature, &finderLikeProcess,
  247.             sizeof (finderLikeProcess), &address)))
  248.         {
  249.             OSErr err2 = noErr;
  250.             fErr = AECreateAppleEvent (eventClass,eventID,&address,
  251.                 kAutoGenerateReturnID,kAnyTransactionID,this);
  252.             err2 = AEDisposeDesc (&address);
  253.             if (!fErr && !(fErr = err2))
  254.             {
  255.                 fSendMode = kAENoReply | kAEAlwaysInteract | kAECanSwitchLayer;
  256.             }
  257.         }
  258.     }
  259. }
  260.  
  261. FinderEvent::~FinderEvent (void)
  262. {
  263.     if (dataHandle)
  264.         fErr = AEDisposeDesc (this);
  265.     if (fReply.dataHandle)
  266.         fErr = AEDisposeDesc (&fReply);
  267. }
  268.  
  269. /////////////////////////////////////////////////////////////////////////////////
  270. #pragma mark -
  271.  
  272. static pascal OSErr MFE_Simple (AEEventID eventID)
  273. {
  274.     OSErr err = noErr;
  275.     FinderEvent finderEvent (kAEFinderEvents,eventID);
  276.     if (!(err = finderEvent.fErr))
  277.         err = finderEvent.Send ( );
  278.     return err;
  279. }
  280.  
  281. static pascal OSErr MFE_HideSpecialWindow (OSType aliasUserType)
  282. {
  283.     OSErr err = noErr;
  284.     FinderEvent finderEvent (kAEFinderEvents,kAEClose);
  285.     if (!(err = finderEvent.fErr))
  286.     {
  287.         MFE_Window finderWindow;
  288.  
  289.         finderWindow.fWindowType                = 0;
  290.         finderWindow.fAliasType                    = 'find';
  291.         finderWindow.fAliasLen                    = 4;
  292.         finderWindow.fAliasRecord.userType        = aliasUserType;
  293.         finderWindow.fAliasRecord.aliasSize        = 0;
  294.  
  295.         if (!(err = AEPutParamPtr (&finderEvent, keyDirectObject,
  296.             typeFinderWindow, &finderWindow, sizeof (finderWindow))))
  297.                 err = finderEvent.Send ( );
  298.     }
  299.  
  300.     return err;
  301. }
  302.  
  303. static pascal OSErr MFE_ShowSpecialWindow
  304.     (AEEventClass eventClass, AEEventID eventID)
  305. {
  306.     FinderEvent finderEvent (eventClass,eventID);
  307.  
  308.     if (finderEvent.fErr)
  309.         return finderEvent.fErr;
  310.     else
  311.         return finderEvent.Send ( );
  312. }
  313.  
  314. static pascal OSErr MFE_AddParentAlias
  315.     (FinderEvent &finderEvent, const AliasRecord **aliasH)
  316. {
  317.     //
  318.     //    The goal here is to add a parent alias to 'finderEvent' as the direct
  319.     //    object as specified by the Apple Event Registry. If 'aliasH' is not a
  320.     //    volume, we add an alias of the parent of 'aliasH'. If 'aliasH' is a
  321.     //    volume, we want to add 'aliasH' itself as the container because lots
  322.     //    of events expect that bizarre behavior. We make a new alias to it
  323.     //    because we have no way of telling whether the incoming alias is a full
  324.     //    alias or not, and Finder demands one (and it tends to throw nasty
  325.     //    tantrums if it's not).
  326.     //
  327.  
  328.     OSErr err = noErr;
  329.  
  330.     FSSpecPtr fssP = FSSpecPtr (NewPtr (sizeof (FSSpec)));
  331.     if (!(err = MemError ( )))
  332.     {
  333.         if (!(err = ::HandToHand ((Handle *) &aliasH)))
  334.         {
  335.             Boolean wasChanged;
  336.             if (!(err = ResolveAlias (nil, AliasHandle (aliasH), fssP,
  337.                 &wasChanged))) // aliasH is a copy
  338.             {
  339.                 if (fssP->parID == fsRtParID ||
  340.                     !(err = FSMakeFSSpec (fssP->vRefNum, fssP->parID, nil, fssP)))
  341.                 {
  342.                     AliasHandle parentAlias;
  343.                     if (!(err = NewAlias (nil,fssP,&parentAlias)))
  344.                     {
  345.                         HLock (Handle (parentAlias));
  346.                         if (!(err = MemError ( )))
  347.                         {
  348.                             Size parentAliasSize =
  349.                                 GetHandleSize (Handle (parentAlias));
  350.                             if (!(err = MemError ( )))
  351.                                 err = AEPutParamPtr (&finderEvent, keyDirectObject,
  352.                                     typeAlias, *parentAlias, parentAliasSize);
  353.                         }
  354.                         DisposeHandle (Handle (parentAlias));
  355.                     }
  356.                 }
  357.             }
  358.             ::DisposeHandle (Handle (aliasH));
  359.             if (!err) err = MemError ( );
  360.         }
  361.         DisposePtr (Ptr (fssP));
  362.         if (!err) err = MemError ( );
  363.     }
  364.  
  365.     return err;
  366. }
  367.  
  368. static pascal OSErr MFE_AddChildAlias
  369.     (AEDescList &selection, const AliasRecord **aliasH)
  370. {
  371.     OSErr err = noErr;
  372.  
  373.     SInt8 hState = HGetState (Handle (aliasH));
  374.     if (!(err = MemError ( )))
  375.     {
  376.         HLock (Handle (aliasH));
  377.         if (!(err = MemError ( )))
  378.         {
  379.             Size aliasSize = GetHandleSize (Handle (aliasH));
  380.             if (!(err = MemError ( )))
  381.             {
  382.                 err = AEPutPtr (&selection,0,typeAlias,*aliasH,aliasSize);
  383.             }
  384.             HSetState (Handle (aliasH), hState);
  385.         }
  386.     }
  387.  
  388.     return err;
  389. }
  390.  
  391. static pascal OSErr MFE_SendSingleSelectionEvent
  392.     (const AliasRecord **aliasH, AEEventID eventID)
  393. {
  394.     OSErr err = noErr;
  395.  
  396.     FinderEvent finderEvent (kAEFinderEvents,eventID);
  397.     if (!(err = finderEvent.fErr))
  398.     {
  399.         if (!(err = MFE_AddParentAlias (finderEvent,aliasH)))
  400.         {
  401.             AEDescList selection = { typeNull, nil };
  402.             if (!(err = AECreateList (nil,0,false,&selection)))
  403.             {
  404.                 if (!(err = MFE_AddChildAlias (selection,aliasH)))
  405.                     if (!(err = AEPutParamDesc (&finderEvent,keySelection,
  406.                         &selection)))
  407.                             err = finderEvent.Send ( );
  408.  
  409.                 AEDisposeDesc (&selection);
  410.             }
  411.         }
  412.     }
  413.  
  414.     return err;
  415. }
  416.  
  417. static pascal OSErr MFE_SendSingleFileEventViaHandle
  418.     (Handle h, AEEventID eventID, DescType descType)
  419. {
  420.     OSErr err = noErr;
  421.  
  422.     FinderEvent finderEvent (kAEFinderEvents,eventID);
  423.     if (!(err = finderEvent.fErr))
  424.     {
  425.         SInt8 hState = HGetState (h);
  426.         if (!(err = MemError ( )))
  427.         {
  428.             HLock (h);
  429.             if (!(err = MemError ( )))
  430.             {
  431.                 Size size = GetHandleSize (h);
  432.  
  433.                 if (!(err = MemError ( )))
  434.                     if (!(err = AEPutParamPtr (&finderEvent, keyDirectObject,
  435.                         descType, *h, size)))
  436.                             err = finderEvent.Send ( );
  437.  
  438.                 HSetState (h, hState);
  439.                 if (!err) err = MemError ( );
  440.             }
  441.         }
  442.     }
  443.  
  444.     return err;
  445. }
  446.  
  447. static pascal OSErr MFE_CreateFinderWindowHandle
  448.     (const AliasRecord **aliasH, MFE_WindowH *fwhp, long windowType = 0)
  449. {
  450.     OSErr err = noErr;
  451.  
  452.     Size size = ::GetHandleSize (Handle (aliasH));
  453.     if (!(err = MemError ( )))
  454.     {
  455.         *fwhp = MFE_WindowH (NewHandle (size + sizeof (MFE_Window) -
  456.             sizeof (AliasRecord)));
  457.         if (!(err = MemError ( )))
  458.         {
  459.             MFE_Window finderWindow;
  460.  
  461.             finderWindow.fWindowType    = windowType;
  462.             finderWindow.fAliasRecord    = **aliasH;
  463.  
  464.             finderWindow.fAliasType        = typeAlias;
  465.             finderWindow.fAliasLen        = size;
  466.  
  467.             MFE_Window *finderWindowP = **fwhp;
  468.             BlockMoveData (*aliasH,&(finderWindowP->fAliasRecord),size);
  469.             *finderWindowP = finderWindow;
  470.         }
  471.     }
  472.  
  473.     return err;
  474. }
  475.  
  476. static pascal OSErr MFE_SendSimpleFinderWindowEvent
  477.     (const AliasRecord **aliasH, AEEventID eventID, long windowType = 0)
  478. {
  479.     OSErr err = noErr;
  480.  
  481.     MFE_WindowH finderWindowH = nil;
  482.     if (!(err = MFE_CreateFinderWindowHandle (aliasH,&finderWindowH,windowType)))
  483.     {
  484.         err = MFE_SendSingleFileEventViaHandle (Handle (finderWindowH),
  485.             eventID, typeFinderWindow);
  486.         DisposeHandle (Handle (finderWindowH));
  487.         if (!err) err = MemError ( );
  488.     }
  489.  
  490.     return err;
  491. }
  492.  
  493. static pascal OSErr MFE_AddDestinationAlias
  494.     (const AliasRecord **destAlias, FinderEvent &finderEvent)
  495. {
  496.     OSErr err = noErr;
  497.  
  498.     SInt8 destAliasState = HGetState (Handle (destAlias));
  499.     if (!(err = MemError ( )))
  500.     {
  501.         HLock (Handle (destAlias));
  502.         if (!(err = MemError ( )))
  503.         {
  504.             Size destAliasSize = GetHandleSize (Handle (destAlias));
  505.  
  506.             if (!(err = MemError ( )))
  507.                 err = AEPutParamPtr (&finderEvent, keyDirectObject, typeAlias,
  508.                     *destAlias, destAliasSize);
  509.  
  510.             HSetState (Handle (destAlias), destAliasState);
  511.             if (!err) err = MemError ( );
  512.         }
  513.     }
  514.  
  515.     return err;
  516. }
  517.  
  518. static pascal OSErr MFE_ResolveAlias (const AliasRecord **aliasH, FSSpecPtr fssP)
  519. {
  520.     Boolean dontCare;
  521.     short aliasCount = 1;
  522.     const unsigned long rulesMask = kARMNoUI | kARMSearch;
  523.  
  524.     return MatchAlias (nil,rulesMask,AliasHandle(aliasH),&aliasCount,
  525.         fssP,&dontCare,nil,nil);
  526. }
  527.  
  528. typedef pascal OSErr (*vParamValidator)
  529.     (const FSSpec &fssToDrag, const FSSpec &fssTarget);
  530.  
  531. static pascal OSErr MFE_DragLow
  532.     (AEEventID eventID, vParamValidator validateParams,
  533.         const AliasRecord **aliasToDrag, const AliasRecord **destAlias)
  534. {
  535.     OSErr err = noErr;
  536.  
  537.     //
  538.     //    If we need to validate our inputs, allocate two FSSpec records
  539.     //    on the heap and resolve the parameter aliases.
  540.     //
  541.  
  542.     if (validateParams)
  543.     {
  544.         FSSpecPtr specToDragP    = nil;
  545.         FSSpecPtr specDestP        = nil;
  546.  
  547.         do
  548.         {
  549.             specToDragP = FSSpecPtr (NewPtr (sizeof (FSSpec)));
  550.             err = MemError ( ); if (err) break;
  551.             specDestP = FSSpecPtr (NewPtr (sizeof (FSSpec)));
  552.             err = MemError ( ); if (err) break;
  553.             err = MFE_ResolveAlias (aliasToDrag,specToDragP);
  554.             if (err) break;
  555.             err = MFE_ResolveAlias (destAlias,specDestP);
  556.             if (err) break;
  557.             err = validateParams (*specToDragP,*specDestP);
  558.         }
  559.         while (false);
  560.  
  561.         if (specToDragP)
  562.             DisposePtr (Ptr (specToDragP));
  563.         if (specDestP)
  564.             DisposePtr (Ptr (specDestP));
  565.     }
  566.  
  567.     //
  568.     //    If there were no errors validating our inputs,
  569.     //    build and send the event.
  570.     //
  571.  
  572.     if (!err)
  573.     {
  574.         AEDescList selection = { typeNull, nil };
  575.  
  576.         do
  577.         {
  578.             FinderEvent finderEvent (kAEFinderEvents,eventID);
  579.             err = finderEvent.fErr;
  580.             if (err) break;
  581.             err = AECreateList (nil,0,false,&selection);
  582.             if (err) break;
  583.             err = MFE_AddChildAlias (selection,aliasToDrag);
  584.             if (err) break;
  585.             err = AEPutParamDesc (&finderEvent,keySelection,&selection);
  586.             if (err) break;
  587.             Point iconPosition = { 0,0 }; // no offset, thank you
  588.             err = AEPutParamPtr (&finderEvent, keyMiscellaneous, typeLongInteger,
  589.                 &iconPosition, sizeof (iconPosition));
  590.             if (err) break;
  591.             err = MFE_AddDestinationAlias (destAlias,finderEvent);
  592.             if (err) break;
  593.             err = finderEvent.Send ( );
  594.         }
  595.         while (false);
  596.  
  597.         if (selection.dataHandle)
  598.             AEDisposeDesc (&selection);
  599.     }
  600.  
  601.     return err;
  602. }
  603.  
  604. /////////////////////////////////////////////////////////////////////////////////
  605. #pragma mark -
  606.  
  607. pascal OSErr MFE_PrintWindow (const AliasRecord **aliasH)
  608. {
  609.     return MFE_SendSimpleFinderWindowEvent (aliasH,kAEPrintWindow);
  610. }
  611.  
  612. pascal OSErr MFE_PageSetup (const AliasRecord **aliasH)
  613. {
  614.     return MFE_SendSimpleFinderWindowEvent (aliasH,kAEPageSetup);
  615. }
  616.  
  617. pascal OSErr MFE_CloseWindow (const AliasRecord **aliasH)
  618. {
  619.     return MFE_SendSimpleFinderWindowEvent (aliasH,kAEClose);
  620. }
  621.  
  622. pascal OSErr MFE_CloseGetInfo (const AliasRecord **aliasH)
  623. {
  624.     return MFE_SendSimpleFinderWindowEvent (aliasH,kAEClose,kAEInfo);
  625. }
  626.  
  627. pascal OSErr MFE_CloseSharing (const AliasRecord **aliasH)
  628. {
  629.     return MFE_SendSimpleFinderWindowEvent (aliasH,kAEClose,kAESharing);
  630. }
  631.  
  632. pascal OSErr MFE_MakeAlias (const AliasRecord **aliasH)
  633. {
  634.     return MFE_SendSingleSelectionEvent (aliasH,kAEAliasSelection);
  635. }
  636.  
  637. pascal OSErr MFE_Duplicate (const AliasRecord **aliasH)
  638. {
  639.     return MFE_SendSingleSelectionEvent (aliasH,kAEDuplicateSelection);
  640. }
  641.  
  642. pascal OSErr MFE_OpenSelection (const AliasRecord **aliasH)
  643. {
  644.     return MFE_SendSingleSelectionEvent (aliasH,kAEOpenSelection);
  645. }
  646.  
  647. pascal OSErr MFE_PrintSelection (const AliasRecord **aliasH)
  648. {
  649.     return MFE_SendSingleSelectionEvent (aliasH,kAEPrintSelection);
  650. }
  651.  
  652. pascal OSErr MFE_OpenGetInfo (const AliasRecord **aliasH)
  653. {
  654.     return MFE_SendSingleSelectionEvent (aliasH,kAEGetInfoSelection);
  655. }
  656.  
  657. pascal OSErr MFE_OpenSharing (const AliasRecord **aliasH)
  658. {
  659.     return MFE_SendSingleSelectionEvent (aliasH,kAEGetPrivilegeSelection);
  660. }
  661.  
  662. pascal OSErr MFE_Reveal (const AliasRecord **aliasH)
  663. {
  664.     return MFE_SendSingleSelectionEvent (aliasH,kAERevealSelection);
  665. }
  666.  
  667. pascal OSErr MFE_PutAway (const AliasRecord **aliasH)
  668. {
  669.     return MFE_SendSingleSelectionEvent (aliasH,kAEPutAwaySelection);
  670. }
  671.  
  672. pascal OSErr MFE_UnmountVolume (short vRefNum)
  673. {
  674.     FSSpecPtr fssP = (FSSpecPtr) ::NewPtr (sizeof (*fssP));
  675.     OSErr err = ::MemError ( );
  676.     if (!err)
  677.     {
  678.         if (!(err = FSMakeFSSpec (vRefNum, fsRtDirID, "\p", fssP)))
  679.         {
  680.             AliasHandle aliasH = nil;
  681.             OSErr err = NewAliasMinimal (fssP, &aliasH);
  682.             if (!err)
  683.             {
  684.                 err = MFE_PutAway (aliasH);
  685.                 DisposeHandle (Handle (aliasH));
  686.                 if (!err) err = MemError ( );
  687.             }
  688.         }
  689.  
  690.         DisposePtr (Ptr (fssP));
  691.         if (!err) err = MemError ( );
  692.     }
  693.     return err;
  694. }
  695.  
  696. pascal OSErr MFE_ShowAbout (void)
  697. {
  698.     return MFE_ShowSpecialWindow (kCoreEventClass,kAEAbout);
  699. }
  700.  
  701. pascal OSErr MFE_ShowClipboard (void)
  702. {
  703.     return MFE_ShowSpecialWindow (kAEFinderEvents,kAEShowClipboard);
  704. }
  705.  
  706. pascal OSErr MFE_HideAbout (void)
  707. {
  708.     return MFE_HideSpecialWindow ('abot');
  709. }
  710.  
  711. pascal OSErr MFE_HideClipboard (void)
  712. {
  713.     return MFE_HideSpecialWindow ('clip');
  714. }
  715.  
  716. #pragma mark -
  717.  
  718. pascal OSErr MFE_Sleep (void)
  719. {
  720.     return MFE_Simple (kAESleep);
  721. }
  722.  
  723. pascal OSErr MFE_Restart (void)
  724. {
  725.     return MFE_Simple (kAERestart);
  726. }
  727.  
  728. pascal OSErr MFE_ShutDown (void)
  729. {
  730.     return MFE_Simple (kAEShutDown);
  731. }
  732.  
  733. pascal OSErr MFE_EmptyTrash (void)
  734. {
  735.     return MFE_Simple (kAEEmptyTrash);
  736. }
  737.  
  738. #pragma mark -
  739.  
  740. static pascal OSErr MFE_CopyParamValidator
  741.     (const FSSpec &fssToDrag, const FSSpec &fssTarget)
  742. {
  743.     //
  744.     //    Finder does an infinite recursion when you attempt to
  745.     //    copy a file over itself. Here we test a file to be moved
  746.     //    against a potential destination directory. If they match,
  747.     //    we claim we were passed bogus parameters, which isn't a lie.
  748.     //
  749.  
  750.     OSErr err = noErr;
  751.  
  752.     CInfoPBPtr cipbp = CInfoPBPtr (NewPtrClear (sizeof (*cipbp)));
  753.     if (!(err = MemError ( )))
  754.     {
  755.         cipbp->dirInfo.ioDrDirID    = fssTarget.parID;
  756.         cipbp->dirInfo.ioVRefNum    = fssTarget.vRefNum;
  757.         cipbp->dirInfo.ioNamePtr    = StringPtr (fssTarget.name);
  758.  
  759.         if (!(err = PBGetCatInfoSync (cipbp)))
  760.             if (fssToDrag.parID == cipbp->dirInfo.ioDrDirID)
  761.                 err = paramErr;
  762.  
  763.         DisposePtr (Ptr (cipbp));
  764.         if (!err) err = MemError ( );
  765.     }
  766.  
  767.     return err;
  768. }
  769.  
  770. static pascal OSErr MFE_MoveParamValidator
  771.     (const FSSpec &fssToDrag, const FSSpec &fssTarget)
  772. {
  773.     //
  774.     //    Finder will happily attempt (and fail) to move something
  775.     //    to a different volume. The item gets moved to the directory
  776.     //    with the same ID on the source volume -- if it exists.
  777.     //    If it doesn't exist, we never hear about the problem and
  778.     //    nothing happens.
  779.     //
  780.     //    Also: moving a file onto itself is dumb, so we call the copy
  781.     //    validator, which checks this for us.
  782.     //
  783.  
  784.     OSErr err = noErr;
  785.  
  786.     if (fssToDrag.vRefNum != fssTarget.vRefNum)
  787.         err = paramErr;
  788.     else
  789.         err = MFE_CopyParamValidator (fssToDrag,fssTarget);
  790.  
  791.     return err;
  792. }
  793.  
  794. pascal OSErr MFE_Copy
  795.     (const AliasRecord **aliasToDrag, const AliasRecord **destAlias)
  796. {
  797.     return MFE_DragLow (kAEDrag,MFE_CopyParamValidator,aliasToDrag,destAlias);
  798. }
  799.  
  800. pascal OSErr MFE_Move
  801.     (const AliasRecord **aliasToDrag, const AliasRecord **destAlias)
  802. {
  803.     return MFE_DragLow (kAEMove,MFE_MoveParamValidator,aliasToDrag,destAlias);
  804. }
  805.